package server

import (
	"context"
	"encoding/json"
	"novel-go/global"
	"novel-go/model/request"
	"novel-go/model/response"
	"novel-go/model/server"
	"strconv"
	"strings"

	"go.uber.org/zap"
)

// SearchBook 实现书籍搜索功能
// 参数:
//
//	req - 包含搜索条件的请求对象
//
// 返回值:
//
//	code - 响应状态码
//	data - 搜索结果列表
func SearchBook(req *request.Request) (code int, data interface{}) {
	// 1. 解析请求参数
	jsonData, _ := json.Marshal(req.Data)
	var queryBook request.QueryBook
	err := json.Unmarshal(jsonData, &queryBook)
	if nil != err {
		return response.InvalidParameter, nil
	}

	// 2. 设置默认分页参数
	if queryBook.Num == 0 {
		queryBook.Num = 30
	}
	// 设置默认排序参数
	offset := queryBook.Page * queryBook.Num

	// 3. 构建Elasticsearch布尔查询条件
	boolQuery := make([]string, 0)

	// 3.1 书籍ID条件
	if len(queryBook.Bid) > 0 {
		boolQuery = append(boolQuery, `{ "terms": { "bid": "`+queryBook.Bid+`" }}`)
	}

	// 3.2 书籍标记条件
	if queryBook.Flag > 0 {
		boolQuery = append(boolQuery, `{ "terms": { "flag": `+strconv.Itoa(queryBook.Flag)+` }}`)
	}

	// 3.3 关键词搜索条件
	if len(queryBook.Keywords) > 0 {
		boolQuery = append(boolQuery, `{ "match": { "keywords": "`+queryBook.Keywords+`" }}`)
	}

	// 3.4 时间范围条件
	if len(queryBook.StartTime) > 0 {
		boolQuery = append(boolQuery, `{
            "range": {
                "create_time": {
                    "gte": "`+queryBook.StartTime+`"
                }
            }
        }`)
	}

	// 3.5 位运算条件
	if queryBook.Value > 0 {
		boolQuery = append(boolQuery, `{
            "script": {
                "script": "(doc['value'].value&`+strconv.Itoa(queryBook.Value)+`)!=0"
            }
        }`)
	}

	// 4. 构建完整Elasticsearch查询
	query := `{
        "_source": {
            "excludes": [
                "keywords"
            ]
        },
        "query": {
            "function_score": {
                "query": {
                    "bool": {
                        "must": [` + strings.Join(boolQuery, ",") + `]
                    }
                },
                "functions": [ 
                    {
                        "script_score": {
                            "script": {
                                "source": "doc['weight'].value * 0.01"
                            }
                        }
                    }
                ],
                "boost_mode": "sum"
            }
        }
    }`

	// 5. 执行Elasticsearch查询
	es := global.FPG_ELASTIC
	res, err := es.Search(
		// 设置搜索上下文为后台上下文
		es.Search.WithContext(context.Background()),
		// 指定搜索的索引名称
		es.Search.WithIndex("book_pool"),
		// 设置搜索请求体内容
		es.Search.WithBody(strings.NewReader(query)),
		// 启用跟踪总命中数
		es.Search.WithTrackTotalHits(true),
		// 启用格式化输出
		es.Search.WithPretty(),
		es.Search.WithSort(strings.Replace(queryBook.Order, " ", ":", 1)), // 排序 输入："create_time asc" → 输出："create_time:asc"
		es.Search.WithFrom(offset),                                        // 从第几条开始返回
		es.Search.WithSize(queryBook.Num),                                 // 返回多少条
	)
	if nil != err {
		global.FPG_LOG.Error("search book error", zap.Error(err))
		return response.InternalServerError, nil
	}
	defer res.Body.Close()

	// 6. 解析查询结果
	var r map[string]interface{}
	if err := json.NewDecoder(res.Body).Decode(&r); err != nil {
		global.FPG_LOG.Error("parsing the response body error", zap.Error(err))
		return response.InternalServerError, nil
	}
	if _, ok := r["error"]; ok {
		return response.InternalServerError, nil
	}

	// 7. 转换为业务对象
	results := make([]server.ResBook, 0)
	for _, hit := range r["hits"].(map[string]interface{})["hits"].([]interface{}) {
		_source := hit.(map[string]interface{})["_source"]
		resBook := &server.ResBook{}
		err := resBook.UndecodeMap(_source)
		if err != nil {
			global.FPG_LOG.Error("parsing the response body error", zap.Error(err))
		}
		results = append(results, *resBook)
	}

	return response.Success, results
}
